import { Fragment, memo, ReactElement, useEffect } from 'react'
import { useUpdate } from 'ahooks'

import { useAntdPopupAnimation } from './useAntdPopupAnimation'

export { useAntdPopupAnimation }

const asyncThrowError = () => {
  setTimeout(() => {
    throw new Error('插槽还未挂载')
  })
}

/** 创建弹层插槽 */
export const createPopupSlot = () => {
  let uniqueId = 0
  const nodeMap = new Map<number, ReactElement>()
  const updateFns: (() => void)[] = []

  return {
    /** 向插槽中插入一个节点，返回的函数可用于更新或销毁该节点 */
    insert: function (node: ReactElement | null): (newNode: ReactElement | null) => void {
      const key = ++uniqueId

      if (node) {
        if (updateFns.length === 0) {
          asyncThrowError()
        } else {
          nodeMap.set(key, node)
          updateFns.forEach(fn => fn())
        }
      }

      return newNode => {
        if (newNode) {
          if (updateFns.length === 0) {
            asyncThrowError()
          } else {
            nodeMap.set(key, newNode)
            updateFns.forEach(fn => fn())
          }
        } else {
          nodeMap.delete(key)
          updateFns.forEach(fn => fn())
        }
      }
    },

    /** 插槽 */
    Slot: memo(function Slot() {
      const update = useUpdate()
      if (!updateFns.includes(update)) updateFns.push(update)

      useEffect(
        () => () => {
          const index = updateFns.findIndex(fn => fn === update)
          if (index > -1) updateFns.splice(index, 1)
          if (updateFns.length === 0) nodeMap.clear() // 重置
        },
        [update],
      )

      return (
        <>
          {Array.from(nodeMap).map(([key, node]) => (
            <Fragment key={key}>{node}</Fragment>
          ))}
        </>
      )
    }),

    useAntdPopupAnimation,
  }
}
